library(dplyr)
library(ggplot2)
library(rbokeh)
sierpinski_triangle <- function(iterations, corners_x, corners_y) {
  point <- runif(2)
  corners <- matrix(c(corners_x, corners_y), ncol = 2)
  result <- matrix(0, nrow = iterations, ncol = 2)
  for (i in 1:iterations) {
    point <- (corners[sample(3, 1),] + point) / 2
    result[i,] <- point
  }
  result
}
sierpinski_tree <- function(iterations) {
  t1 <- sierpinski_triangle(iterations, c(-0.5, 0.5, 0), c(-1, -1, 0))
  t2 <- sierpinski_triangle(2 * iterations, c(-1, 1, 0), c(-2.5, -2.5, -0.5))
  t3 <- sierpinski_triangle(4 * iterations, c(-2, 2, 0), c(-5.5, -5.5, -1.5))
  rbind(t1, t2, t3) %>% matrix(ncol = 2) %>% as.data.frame
}
set.seed(1234)
df <- sierpinski_tree(10000)
df2 <- df[sample(nrow(df)),][1:30,] %>% 
  mutate(color = as.factor(sample(1:5, length(V1), replace = TRUE)),
         shape = as.factor(sample(1:3, length(V1), replace = TRUE)))
figure(xgrid=FALSE, ygrid=FALSE, xaxes=FALSE, yaxes=FALSE) %>%
  ly_points(V1, V2, data = df, size = 2, color = "green", fill_alpha = 1) %>%
  ly_points(V1, V2, data = df2, size = 20, color = color, glyph = shape, fill_alpha = 1, legend = FALSE) %>%
  ly_points(0, 0, color = "yellow", size = 40, line_width= 4, glyph = 8)
LS0tDQp0aXRsZTogIlByYWNhIGRvbW93YSAtIENob2lua2EiDQphdXRob3I6ICJBcnR1ciBNaW5vcmN6eWsiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJib2tlaCkNCmBgYA0KDQpgYGB7cn0NCnNpZXJwaW5za2lfdHJpYW5nbGUgPC0gZnVuY3Rpb24oaXRlcmF0aW9ucywgY29ybmVyc194LCBjb3JuZXJzX3kpIHsNCiAgcG9pbnQgPC0gcnVuaWYoMikNCiAgY29ybmVycyA8LSBtYXRyaXgoYyhjb3JuZXJzX3gsIGNvcm5lcnNfeSksIG5jb2wgPSAyKQ0KICByZXN1bHQgPC0gbWF0cml4KDAsIG5yb3cgPSBpdGVyYXRpb25zLCBuY29sID0gMikNCiAgZm9yIChpIGluIDE6aXRlcmF0aW9ucykgew0KICAgIHBvaW50IDwtIChjb3JuZXJzW3NhbXBsZSgzLCAxKSxdICsgcG9pbnQpIC8gMg0KICAgIHJlc3VsdFtpLF0gPC0gcG9pbnQNCiAgfQ0KICByZXN1bHQNCn0NCg0Kc2llcnBpbnNraV90cmVlIDwtIGZ1bmN0aW9uKGl0ZXJhdGlvbnMpIHsNCiAgdDEgPC0gc2llcnBpbnNraV90cmlhbmdsZShpdGVyYXRpb25zLCBjKC0wLjUsIDAuNSwgMCksIGMoLTEsIC0xLCAwKSkNCiAgdDIgPC0gc2llcnBpbnNraV90cmlhbmdsZSgyICogaXRlcmF0aW9ucywgYygtMSwgMSwgMCksIGMoLTIuNSwgLTIuNSwgLTAuNSkpDQogIHQzIDwtIHNpZXJwaW5za2lfdHJpYW5nbGUoNCAqIGl0ZXJhdGlvbnMsIGMoLTIsIDIsIDApLCBjKC01LjUsIC01LjUsIC0xLjUpKQ0KICByYmluZCh0MSwgdDIsIHQzKSAlPiUgbWF0cml4KG5jb2wgPSAyKSAlPiUgYXMuZGF0YS5mcmFtZQ0KfQ0KDQpzZXQuc2VlZCgxMjM0KQ0KZGYgPC0gc2llcnBpbnNraV90cmVlKDEwMDAwKQ0KZGYyIDwtIGRmW3NhbXBsZShucm93KGRmKSksXVsxOjMwLF0gJT4lIA0KICBtdXRhdGUoY29sb3IgPSBhcy5mYWN0b3Ioc2FtcGxlKDE6NSwgbGVuZ3RoKFYxKSwgcmVwbGFjZSA9IFRSVUUpKSwNCiAgICAgICAgIHNoYXBlID0gYXMuZmFjdG9yKHNhbXBsZSgxOjMsIGxlbmd0aChWMSksIHJlcGxhY2UgPSBUUlVFKSkpDQpgYGANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpmaWd1cmUoeGdyaWQ9RkFMU0UsIHlncmlkPUZBTFNFLCB4YXhlcz1GQUxTRSwgeWF4ZXM9RkFMU0UpICU+JQ0KICBseV9wb2ludHMoVjEsIFYyLCBkYXRhID0gZGYsIHNpemUgPSAyLCBjb2xvciA9ICJncmVlbiIsIGZpbGxfYWxwaGEgPSAxKSAlPiUNCiAgbHlfcG9pbnRzKFYxLCBWMiwgZGF0YSA9IGRmMiwgc2l6ZSA9IDIwLCBjb2xvciA9IGNvbG9yLCBnbHlwaCA9IHNoYXBlLCBmaWxsX2FscGhhID0gMSwgbGVnZW5kID0gRkFMU0UpICU+JQ0KICBseV9wb2ludHMoMCwgMCwgY29sb3IgPSAieWVsbG93Iiwgc2l6ZSA9IDQwLCBsaW5lX3dpZHRoPSA0LCBnbHlwaCA9IDgpDQpgYGANCg0K